/**
 * 判断变量是否为 null
 * ======================================
 * @param val
 * @returns {boolean}
 */
export const isNull = (val) => {
  return val === null;
};

/**
 * 睡眠等待(单位：毫米)
 * ======================================
 * @param ms
 * @returns {Number}
 */
export const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};

/**
 * 判断是变量是否未定义
 * ======================================
 * @param val
 * @returns {boolean}
 */
export const isUndefined = (val) => {
  return typeof val === "undefined";
};

/**
 * ES6 中的 Object.assign() 方法
 * ======================================
 * @param target
 * @param varArgs
 * @returns {any}
 */
export const assign = (target, varArgs) => {
  if (target === null || target === undefined) {
    throw new TypeError("Cannot convert undefined or null to object");
  }

  let to = Object(target);

  for (let index = 1; index < arguments.length; index++) {
    let nextSource = arguments[index];

    if (nextSource !== null && nextSource !== undefined) {
      for (let nextKey in nextSource) {
        // Avoid bugs when hasOwnProperty is shadowed
        if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
          to[nextKey] = nextSource[nextKey];
        }
      }
    }
  }

  return to;
};

/**
 * 创建并下载文件
 * ====================================================
 * @param {String} fileName 文件名
 * @param {String} content  文件内容
 */
export const createAndDownloadFile = (fileName, content, type = null) => {
  const $blob = new Blob([content], type);
  const $anchor = document.createElement("a");

  $anchor.download = fileName;
  $anchor.href = URL.createObjectURL($blob);
  $anchor.click();

  URL.revokeObjectURL($blob);
};

/**
 * 防抖函数
 * =============================================================
 * @param fun
 * @param delay
 * @returns {Function}
 */
export const debounce = (fun, delay) => {
  let timer = null;
  let delays = delay || 300;
  return function (args) {
    let that = this;
    let _args = args;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fun.call(that, _args);
    }, delays);
  };
};

/**
 * 截流函数
 * =============================================================
 * @param fn
 * @param wait
 * @returns {Function}
 */
export const throttle = (fn, wait) => {
  let inThrottle;
  let lastFn;
  let lastTime;

  return function () {
    const context = this;
    const args = arguments;

    if (!inThrottle) {
      fn.apply(context, args);
      lastTime = Date.now();
      inThrottle = true;
    } else {
      clearTimeout(lastFn);
      lastFn = setTimeout(function () {
        if (Date.now() - lastTime >= wait) {
          fn.apply(context, args);
          lastTime = Date.now();
        }
      }, Math.max(wait - (Date.now() - lastTime), 0));
    }
  };
};

/**
 * 比较版本大小
 * =============================================================
 * @param preVersion
 * @param lastVersion
 * @returns {number}
 */
export const versionCompare = (preVersion = "", lastVersion = "") => {
  const sources = preVersion.split(".");
  const last = lastVersion.split(".");
  const len = Math.max(sources.length, last.length);
  let result = 0;

  for (let i = 0; i < len; i++) {
    const preValue = sources.length > i ? sources[i] : 0;
    const preNum = isNaN(Number(preValue)) ? preValue.charCodeAt() : Number(preValue);
    const lastValue = last.length > i ? last[i] : 0;
    const lastNum = isNaN(Number(lastValue)) ? lastValue.charCodeAt() : Number(lastValue);

    if (preNum < lastNum) {
      result = -1;
      break;
    } else if (preNum > lastNum) {
      result = 1;
      break;
    }
  }

  return result;
};
